package org.sunspotworld;

import com.sun.spot.sensorboard.peripheral.IAccelerometer3D;
//import com.sun.spot.sensorboard.peripheral.IAccelerometer3DThresholdListener;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.sensorboard.peripheral.ISwitchListener;
import com.sun.spot.sensorboard.peripheral.ITriColorLED;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.util.Random;

/**
 * 
 * @author Dani
 */
class Game implements ISwitchListener, Protocol, GameStates {

    private Main main;
    private ITriColorLED[] leds;
    private ISwitch leftSwitch;
    private ISwitch rightSwitch;
    private IAccelerometer3D accelerometer;

    //state
    private int currentState;
    private int oldState;
    
    //potatoe
    private long potatoe;
    private int potatoeLifetimeFactor;
    private int oldPotatoeLifetimeFactor;
    private long receiveTime;
    private int numberOfActivePlayers;  //This variable is used to determine weither the game is over or not


    //score
    private int score;

    //gametimestamp
    private long gameTime;

    public Game(Main main) {
        this.main = main;
        leds = EDemoBoard.getInstance().getLEDs();
        leftSwitch = EDemoBoard.getInstance().getSwitches()[0];
        rightSwitch = EDemoBoard.getInstance().getSwitches()[1];
        accelerometer = EDemoBoard.getInstance().getAccelerometer();
        currentState = INITIAL;
        potatoe = 0;
        score = 0;
        oldState = 99;
        receiveTime = 0;
        potatoeLifetimeFactor = 15000;
        oldPotatoeLifetimeFactor = 99;
        gameTime = 0;
        numberOfActivePlayers = -1;
    }

    public void setGameTime(long gameTime) {
        score = 0;
        this.gameTime = System.currentTimeMillis() + gameTime;
    }

    public int getCurrentState() {
        return currentState;
    }

    public void setup() {
        leftSwitch.addISwitchListener(this);
        rightSwitch.addISwitchListener(this);
    }

    /**
     * Command to set the interface LEDs oon a SunSPOT
     */
    private void display() {
        if(oldState != currentState || oldPotatoeLifetimeFactor != potatoeLifetimeFactor){
            
            oldState = currentState;
            oldPotatoeLifetimeFactor = potatoeLifetimeFactor;

            resetLeds();
            Utils.sleep(1);//for the leds
        
        
            switch(currentState){
                case INITIAL:
                    for(int i = 0; i < leds.length; ++i) {
                    leds[i].setRGB(0, 0, 10);
                    leds[i].setOn();
                    }
                    break;
                case HASPOTATOE:
                    leds[2].setRGB(10, 10, 0);
                    leds[2].setOn();
                    leds[3].setRGB(10, 10, 0);
                    leds[3].setOn();
                    leds[4].setRGB(10, 10, 0);
                    leds[4].setOn();
                    leds[5].setRGB(10, 10, 0);
                    leds[5].setOn();
                    break;
                case WAITINGFORPOTATOE:
                    leds[0].setRGB(0, 10, 10);
                    leds[0].setOn();
                    leds[1].setRGB(0, 10, 10);
                    leds[1].setOn();
                    leds[6].setRGB(0, 10, 10);
                    leds[6].setOn();
                    leds[7].setRGB(0, 10, 10);
                    leds[7].setOn();
                    break;
                case CHOOSEPOTATOELIFETIME:
                    if(potatoeLifetimeFactor  < 120000){
                        for(int i = 0; i<potatoeLifetimeFactor/15000;++i) {
                            leds[i].setRGB(10, 0, 0);
                            leds[i].setOn();
                        }

                        for(int i = potatoeLifetimeFactor/15000; i < leds.length; ++i) {
                            leds[i].setRGB(0, 0, 10);
                            leds[i].setOn();
                        }
                    } else if(potatoeLifetimeFactor <= 2400000) {
                         for(int i = 0; i<potatoeLifetimeFactor/300000;++i) {
                            leds[i].setRGB(10, 10, 0);
                            leds[i].setOn();
                        }

                        for(int i = potatoeLifetimeFactor/300000; i < leds.length; ++i) {
                            leds[i].setRGB(10, 0, 0);
                            leds[i].setOn();
                        }
                    }
                    break;
                case LOSER:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setColor(LEDColor.RED);
                        leds[i].setRGB(10, 0, 0);
                        leds[i].setOn();
                    }
                    break;
                case WINNER:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setRGB(10, 10, 10);
                        leds[i].setOn();
                    }
                    break;
                case WAIT:
                    for(int i = 0; i < leds.length; ++i) {
                        leds[i].setRGB(0, 0, 10);
                        leds[i].setOn();
                    }
                    break;
            }
        }
    }

    private void resetLeds() {
        for(int i = 0; i < leds.length; ++i) {
            leds[i].setOff();
        }
    }

    //gets called constantly so a seperate thread is not necessary
    public void update() {
        if(gameTime >= System.currentTimeMillis() || currentState == INITIAL || gameTime == 0) {
            if(numberOfActivePlayers == 0) { // if its 0 it means all spots died in this round
                currentState = WINNER;
                score++;
                main.resetConnections(); // Put all connections back cuz everyone is back in the game
                System.out.println("WINNER: " + score);
                numberOfActivePlayers--;
            } else {
                // Hold the potatoe for 2 seconds
                if(System.currentTimeMillis() - receiveTime > 1000){
                    if(currentState == HASPOTATOE && potatoe != 0) {
                        if(potatoe <= System.currentTimeMillis()) {
                            currentState = LOSER;
                            main.setOutOfGame(); // Otherwise it replies on broadcast messages send by the ping method while its a looser now
                            if(main.getActiveConnections().size() >= 1) {
                                while(main.getPingableConnections().size() == 0) {
                                    System.out.println("ARE_YOU_THERE_CUZ_IM_DEAD!");
                                    main.sendPingMessage("ARE_YOU_THERE");
                                }
                                String adress = generateRandomAdress();
                                if(adress !=null) {
                                    potatoe = generatePotatoeLifeTime();
                                    numberOfActivePlayers--;
                                    main.sendConnectionMessage(POTATOE + " " + potatoe + " " + potatoeLifetimeFactor + " " + numberOfActivePlayers, adress);
                                    // we set numberOfActivePlayers back for this spot cuz otherwise when 2 spots are left
                                    // and this method gets recalled it recognizes itself as a winner, youll
                                    // get 2 winners
                                    numberOfActivePlayers++;
                                    main.massMessage(DEADPLAYER+"");
                                    main.resetAllPingConnections(); // clean pingableConnections cuz potato is gone
                                }
                            }
                            potatoe = 0;
                        } else {
                            try {
                                double accelX = accelerometer.getAccelX();
                                if (accelX > 2 || accelX < -2) {
                                    //main.testConnections();
                                    main.sendPingMessage("ARE_YOU_THERE");
                                    String adress = generateRandomAdress();
                                    if(main.getPingableConnections().size() >= 1) {
                                        if(!(adress.equalsIgnoreCase(""))){
                                            main.sendConnectionMessage(POTATOE + " " + potatoe+ " " + potatoeLifetimeFactor + " " + numberOfActivePlayers, adress);
                                            main.resetAllPingConnections(); // clean pingableConnections cuz potato is gone
                                            currentState = WAITINGFORPOTATOE;
                                            potatoe = 0;
                                        } else {
                                            adress = "No adres within radius found";
                                        }
                                    }
                                }
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                        }
                    } else if (currentState == WAITINGFORPOTATOE) {
                        main.replyToPing();
                    }
                }
            }
        } else {
            currentState = INITIAL;
            potatoe = 0;
        }
        display();
    }

    private String generateRandomAdress() {
        Random r = new Random();
        String adress = "";
        if(main.getPingableConnections().size() > 0 ) {
            Connection con = (Connection) main.getPingableConnections().elementAt((int) (r.nextDouble() * main.getPingableConnections().size()));
            adress = con.getAddress();
            System.out.println(adress);
        } 
        return adress;
    }

    /**
     * handles recieving of messages
     * @param message
     */
    public void receiveMessage(String message, String addressNumber) {
        String[] parts = main.separateStrings(message);
        int protocolNumber = Integer.parseInt(parts[0]);
        for(int i = 0; i<parts.length; i++){
            System.out.println("PARTS: "+parts[i]);
        }
        oldState = currentState;

        

        switch(protocolNumber){
            case STARTGAME:
                currentState = WAITINGFORPOTATOE;
                main.setInGame();
                main.listenToHost();
                main.replyToPing();
                break;
            case POTATOE:
                numberOfActivePlayers = Integer.parseInt(parts[3]);
                if(currentState != LOSER) {
                    currentState = HASPOTATOE;
                    potatoe = Long.parseLong(parts[1]);
                    potatoeLifetimeFactor =Integer.parseInt(parts[2]);
                    receiveTime = System.currentTimeMillis();             
                }
                break;
           case DEADPLAYER:
                main.setConnectionToIdle(addressNumber);              
                break;
            case NEWROUND:
                main.resetConnections();
                break;
            case WAITFORSTART:
                currentState = WAIT;
                break;
        }
    }

    /**
     * generates an endtime
     * @return the timestamp from current time + time for a potato to end
     */
    private long generatePotatoeLifeTime() {
        Random r = new Random();
        long random = 0;
        
        while(random < (potatoeLifetimeFactor / 2) ){
            random = r.nextInt(potatoeLifetimeFactor);
        }

        return System.currentTimeMillis() + random;
    }

    public int getScore() {
        return score;
    }

    public void switchPressed(ISwitch sw) {
        if(leftSwitch.isClosed() && rightSwitch.isClosed()) {
            switch(currentState) {
                case CHOOSEPOTATOELIFETIME:
                    currentState = HASPOTATOE;
                    potatoe = 0;
                    // we gaan nieuwe ronde starten, dus zet alle connections weer terug
                    main.resetConnections();
                    /*Hier misschien methode inbouwen dat niet in activeConnections kijkt maar pingableConnections*/
                    main.massMessage(""+STARTGAME);
                    main.setInGame();
                    numberOfActivePlayers=main.getActiveConnections().size();
                    potatoe = generatePotatoeLifeTime();
                    break;
            }
       } else if(sw == leftSwitch) {
            switch(currentState){
                case CHOOSEPOTATOELIFETIME:
                    if(potatoeLifetimeFactor > 15000 && potatoeLifetimeFactor <= 120000) {
                        potatoeLifetimeFactor-=15000;
                    } else if (potatoeLifetimeFactor == 300000) {
                        potatoeLifetimeFactor-=180000;
                    } else if (potatoeLifetimeFactor >300000 && potatoeLifetimeFactor <= 2400000){
                        potatoeLifetimeFactor-=300000;
                    }
                    potatoe = generatePotatoeLifeTime();
                    break;
                case INITIAL:
                    currentState = CHOOSEPOTATOELIFETIME;
                    main.massMessage(""+WAITFORSTART);
                    break;
                case WINNER:
                    main.massMessage(""+NEWROUND);
                    currentState = CHOOSEPOTATOELIFETIME;
                    potatoeLifetimeFactor = 15000;
                    break;
            }
        } else if(sw == rightSwitch) {

            switch(currentState){

                case CHOOSEPOTATOELIFETIME:
                    if(potatoeLifetimeFactor < 120000) {
                        potatoeLifetimeFactor+=15000;
                    } else if(potatoeLifetimeFactor == 120000) {
                        potatoeLifetimeFactor+=180000;
                    } else if (potatoeLifetimeFactor < 2400000 ) {
                        potatoeLifetimeFactor+= 300000;
                    }
                    potatoe = generatePotatoeLifeTime();
                    break;
                case INITIAL:
                    currentState = CHOOSEPOTATOELIFETIME;
                    main.massMessage(""+WAITFORSTART);
                    break;
                case WINNER:
                    main.massMessage(""+NEWROUND);
                    currentState = CHOOSEPOTATOELIFETIME;
                    potatoeLifetimeFactor = 15000;
                    break;
            }
        }
    }

    public void switchReleased(ISwitch sw) {
    }
}
